#include "FlexScanner.h"
#include "FlexDefs.h"
#include "../smtp/data/SMTPDefaults.h"

int yyFlexLexer::yylex()    // not called: overruled by
{                           // Scanner::yylex()
    return 0;
}

#include "BisonParser.h"

using namespace kc_sf;

// ------------------------------------------------------------------ //

FlexScanner::FlexScanner( std::istream *in, std::ostream *out )
: yyFlexLexer( in, out ), 
  fs_input( in )
{
	fs_lines = fs_bytes = fs_bytes_in_line = fs_last_line_length = 
    fs_last_entity_start = 0;
    fs_last_line = new char[ MAX_LINE_LENGTH + 1 ];
	for( unsigned int i = 0; i < MAX_LINE_LENGTH + 1; ++i )
		fs_last_line[i] = '\0';
}

// ------------------------------------------------------------------ //

FlexScanner::~FlexScanner()  
{
    delete fs_last_line;
}

// ------------------------------------------------------------------ //

// wczytywanie bloków znaków ze strumienia do bufora fs_last_line
// ( docelowo do flex'a )
int FlexScanner::readInput( char *buffer, int max_size )
{
	if( max_size <= 0 || fs_input->eof() || fs_input->fail() )
        return 0;
        
	// ostatnio odczytano całą linię - wczytaj nową
	if( fs_last_line_length <= 0 )
	{
		fs_input->getline( fs_last_line, MAX_LINE_LENGTH );    // miejsce na '\0'
        fs_bytes_in_line = 0;
		++ fs_lines;
		
		fs_last_line_length = fs_input->gcount();

		if( fs_last_line_length > 0 ) {
            fs_last_line[ fs_last_line_length - 1 ] = '\n';    // getline nie wczytuje \n
            fs_last_line[ fs_last_line_length ] = '\0';     
        }
	}
	
	int read = ( fs_last_line_length < max_size )   // ilość odczytanych znaków
               ? fs_last_line_length : max_size;
               
    for( int i = 0; i < read; ++i )
        buffer[i] = fs_last_line[i];
	fs_last_line_length -= read;

	// coś pozostało nie przeczytane - przesuń bufor 
    if( fs_last_line_length > 0 ) 
    {
        for( int i = 0; i < fs_last_line_length; ++i )
            fs_last_line[i] = *(fs_last_line + max_size + i);
    }
	
	return read;
}

// ------------------------------------------------------------------ //

// zwraca liczbę odczytanych linii
unsigned int FlexScanner::linesRead() const
{
    return fs_lines;
}

// ------------------------------------------------------------------ //

// zwraca liczbę odczytanych bajtów
unsigned int FlexScanner::bytesRead() const
{
    return fs_bytes;
}

// ------------------------------------------------------------------ //

// zwraca ostatnio odczytaną linię w formie napisu
std::string FlexScanner::lastlineRead() const
{
    return std::string( fs_last_line );
}

// ------------------------------------------------------------------ //

int	FlexScanner::newToken( yystype_struct *t,               // wskaźnik na token
                           const char * const &value,  	   	// tekst przechowywany w tokenie
                           int type )                      	// typ tokena
{	
	Token new_token( value, type );
	fs_tokens.push_back( new_token );

    // uaktualnienie danych dot. pozycji w strumieniu
    fs_bytes += new_token.value().size();
    fs_bytes_in_line += new_token.value().size();

	// iterator na ostatni element kolekcji tokenów, 
    // przekazywany przez skaner parserowi
	t->yTokenIterator = -- fs_tokens.end();

	// jesli to BOUNDARY lub BOUNDARY_END usuwa -- z poczatku i konca
	if( type == yy::BisonParser::token::BOUNDARY )
	{
		std::string tmp = t->yTokenIterator->value();
		t->yTokenIterator->setValue( tmp.substr( 2, tmp.size() - 2 ) );
	}
	else if( type == yy::BisonParser::token::BOUNDARY_END )
	{
		std::string tmp = t->yTokenIterator->value();
		t->yTokenIterator->setValue( tmp.substr( 2, tmp.size() - 4 ) );
	}

	return type;	
}

// ------------------------------------------------------------------ //

void FlexScanner::error() const
{
    std::string token = ( --fs_tokens.end() )->value();
    std::cerr << "\n\tBledny token: \"" << token
            << "\", \n\tlinia: " << fs_lines 
            << ", pozycja: " << fs_bytes_in_line - token.size()
            << std::endl << std::endl;
    std::cerr << "\t" << fs_last_line << "\t";
    for( unsigned int i = 0; i < fs_bytes_in_line; ++ i )
    {
        if( fs_last_line[i] == '\t' )
            std::cerr << "\t";
        else
            std::cerr << " ";
    }
    std::cerr << "\t";
    for( unsigned int i = fs_bytes_in_line - token.size(); 
         i < token.size(); 
         ++i )
    {
        std::cerr << "^";
    }
    std::cerr << std::endl;
}

// ------------------------------------------------------------------ //

TokenCollection::const_iterator FlexScanner::tokensEnd() const
{
	return fs_tokens.end();
}

// ------------------------------------------------------------------ //

TokenCollection::const_iterator FlexScanner::lastToken() const 	  // ostatni rozpoznany token
{
	TokenCollection::const_iterator end = fs_tokens.end();
	if( fs_tokens.begin() == end )
		return end;

	return -- end;
}
